﻿/********************************************************************************/
/* 	gamecore.d																	*/
/*------------------------------------------------------------------------------*/
/*	製作		（　゜ワ゜）ノ　／　松久貫太									*/
/*	製作開始　	2008/01/03														*/
/*	MAIL		omega@personal.email.ne.jp										*/
/*	URL		http://nagoya.cool.ne.jp/o_mega										*/
/*																				*/
/*	このソースは「やわらかライセンス」の元で配布されています。					*/
/*-更新履歴---------------------------------------------------------------------*/
/*	2008/01/04																	*/
/*-その他-----------------------------------------------------------------------*/
/*	なし																		*/
/********************************************************************************/

private import state;
private import hell2;
private import boot;
private import actor;
private import vector;
private import keypad;
private import clickable;

import config;

private import character;
private import map;

/********************************************************************************/

ConfigParser configparser = null;
const static string CONFIG_PATH = "config.ini";

/* GameMain *********************************************************************/
/*	ゲーム本体の状態															*/
/********************************************************************************/

class GameMain : GameState
{
public:
	int timer;
	Map map;
	CharacterPool charpool;
	
	ClickablePool menu;
	ClickablePool chart_switch;
	ClickablePool economy_switch;
	ClickablePool speed_switch;
	
	int cursor_x;
	int cursor_y;
	int mouse_x;
	int mouse_y;
	
	Keypad keypad;
	
	double view_point_x;
	double view_point_y;
	
	Character target;
	
	PlayChart chart;
	
	this()
	{
		// 各種初期化
		timer = 0;
		configparser = new ConfigParser();
		configparser.load(CONFIG_PATH);
		
		int mapw = configparser.getint("MAP_WIDTH");
		int maph = configparser.getint("MAP_HEIGHT");
		map = new Map(this , mapw , maph);
		charpool = new CharacterPool(this , 512 , mapw , maph);
		
		view_point_x = getScreenWidth() / 2 - map.toViewX(mapw / 2 , maph / 2);
		view_point_y = getScreenHeight() / 2 - map.toViewY(mapw / 2 , maph / 2);
		
		keypad = new Keypad();
		
		chart = new PlayChart(this);
		
		target = null;
		
		// 画面下・ツールメニュー
		menu = new ClickablePool(false /* 非選択状態は選べない */);
		menu.add("del" , new Vec3(getScreenWidth() - ImageButton.BUTTON_WIDTH*4
			, getScreenHeight() - ImageButton.BUTTON_HEIGHT ,0)
			, ImageButton.TYPE.DEL);
		menu.add("herbicide" , new Vec3(getScreenWidth() - ImageButton.BUTTON_WIDTH*3
			, getScreenHeight() - ImageButton.BUTTON_HEIGHT ,0)
			, ImageButton.TYPE.HERBICIDE);
		menu.add("manage_ray" , new Vec3(getScreenWidth() - ImageButton.BUTTON_WIDTH*2
			, getScreenHeight() - ImageButton.BUTTON_HEIGHT ,0)
			, ImageButton.TYPE.MANAGE_RAY);
		menu.add("call_nico" , new Vec3(getScreenWidth() - ImageButton.BUTTON_WIDTH*1
			, getScreenHeight() - ImageButton.BUTTON_HEIGHT ,0)
			, ImageButton.TYPE.CALL_NICO);
		menu.add("up" , new Vec3(getScreenWidth() - ImageButton.BUTTON_WIDTH*2
			, getScreenHeight() - ImageButton.BUTTON_HEIGHT * 2 ,0)
			, ImageButton.TYPE.UP);
		menu.add("fence" , new Vec3(getScreenWidth() - ImageButton.BUTTON_WIDTH*1
			, getScreenHeight() - ImageButton.BUTTON_HEIGHT * 2 ,0)
			, ImageButton.TYPE.FENCE);
		
		// 画面上・チャートスイッチ
		chart_switch = new ClickablePool();
		chart_switch.add("on" , new Vec3(getScreenWidth() - 64*2 , 0 ,0)
			, ImageButton.TYPE.CHART);
		
		// 画面上・エコノミースイッチ
		economy_switch = new ClickablePool();
		economy_switch.add("on" , new Vec3(getScreenWidth() - 64 , 0 ,0)
			, ImageButton.TYPE.ECONOMY);
		
		// 画面上・速度調整スイッチ
		speed_switch = new ClickablePool(false /* 非選択状態は選べない */);
		speed_switch.add("play" , new Vec3(getScreenWidth() - 32*3 , 16 ,0)
			, ImageButton.TYPE.PLAY);
		speed_switch.add("stop" , new Vec3(getScreenWidth() - 32*4 , 16 ,0)
			, ImageButton.TYPE.STOP);
		speed_switch.add("ksk" , new Vec3(getScreenWidth() - 32*2 , 16 ,0)
			, ImageButton.TYPE.KSK);
		speed_switch.add("danger" , new Vec3(getScreenWidth() - 32*1 , 16 ,0)
			, ImageButton.TYPE.DANGER);
	}
	
	void move()
	{
		// マップ及びキャラクタ系移動処理
		int loop = 0;
		if(speed_switch.getSelected() == "stop") loop = 0;
		if(speed_switch.getSelected() == "play") loop = 1;
		if(speed_switch.getSelected() == "ksk") loop = 5;
		if(speed_switch.getSelected() == "danger") loop = 25;
		
		if(loop > 0){
			for(int t=0;t<loop;t++){
				timer++;
				if(timer % (40 * 5) == 0) chart.addChart(charpool , map);
				map.update();
				charpool.move();
			}
		}else{
			charpool.updateBacket();
		}
		
		
		// マウス座標取得
		int o_cursor_x = cursor_x , o_cursor_y = cursor_y;
		mouse_x = Hell_getMouseX();
		mouse_y = Hell_getMouseY();
		cursor_x = map.toMapX(mouse_x,mouse_y);
		cursor_y = map.toMapY(mouse_x,mouse_y);
		
		// メニューとか処理
		menu.getMouseClick();
		chart_switch.getMouseClick();
		economy_switch.getMouseClick();
		speed_switch.getMouseClick();
		
		string menucmd = menu.getSelected();
		
		if((Hell_isPressMouse() & 0x01) && onMouseMap()){
			// マップをいじる操作とかいろいろ(左クリック系
			switch(menucmd){
			case "del":
				// 削除　コマンド
				map.set(cursor_x , cursor_y , MapChip.TYPE.NONE);
				break;
				
			case "herbicide":
				// 除草剤　コマンド
				for(int x=-4;x<5;x++){
					for(int y=-4;y<5;y++){
						map.setGrass(cursor_x + x, cursor_y + y , 0);
					}
				}
				break;
			
			case "manage_ray":
				// 運営レーザー　コマンド
				// TODO:実装する
				break;
				
			case "call_nico":
				if(!(Hell_isPushMouse() & 0x01)) break;
				// ニコ厨を呼ぶ　コマンド
				if(map.inRange(cursor_x,cursor_y)){
					Character c = charpool.set( new Vec3( cursor_x,cursor_y , 0)
						, Character.TYPE.NICOCHU);
					if(c) c.selectNewDirection();
				}else{
					charpool.entryFromMapBorder(Character.TYPE.NICOCHU);
				}
				break;
			
			case "up":
				// うp　コマンド
				map.set(cursor_x , cursor_y , MapChip.TYPE.MOVIE);
				break;
			
			case "fence":
				// 仕切り　コマンド
				map.set(cursor_x , cursor_y , MapChip.TYPE.FENCE);
				break;
				
			default:
				Hell_write("Unknown menu command");
				break;
			}
		}
		// 右クリック
		if(Hell_isPushMouse() & 0x04){
			// 移動
			view_point_x = -(Hell_getMouseX() - getScreenWidth() / 2) + map.draw_ofs_x;
			view_point_y = -(Hell_getMouseY() - getScreenHeight() / 2) + map.draw_ofs_y;
		}
		
		// ゲームパッドorキーボードでソワカちゃん出現&消える
		if(keypad.isPushCancel()){
			if(charpool.count(Character.TYPE.VC_MK) < 1){
				if(map.inRange(cursor_x,cursor_y)){
					charpool.set( new Vec3( cursor_x,cursor_y , 0)
							, Character.TYPE.VC_MK);
				}
			}else{
				charpool.removeCharacter(Character.TYPE.VC_MK);
			}
		}
		
		// 視点移動
		map.draw_ofs_x = map.draw_ofs_x * 0.9 + view_point_x * 0.1;
		map.draw_ofs_y = map.draw_ofs_y * 0.9 + view_point_y * 0.1;
		
		
		// カーソルが動いていたら、詳細表示するキャラクタ座標を更新する
		if(cursor_x != o_cursor_x || cursor_y != o_cursor_y){
			Character c[] = charpool.getCharacterAtMap(cursor_x , cursor_y);
			if(c && c[0]){
				target = c[0];
			}
		}
	}
	
	void draw()
	{
		// エコノミー時は3フレに１回しか描かない
		static int economy_timer = 0;
		if(economy_switch.getSelected() != "" && (economy_timer++) % 3 != 0) return;
		
		// 作画開始
		Hell_begin();
		resetPerspective();
		Hell_setAlpha(HELL_ALPHA_NORMAL);
		
		map.draw();
		
		// カーソル
		if(onMouseMap()){
			MapChip.drawCursor(map.toViewX(cursor_x,cursor_y) 
				, map.toViewY(cursor_x,cursor_y)
				, (timer / 5) % 4);
				
			// マップ情報ウインドウ	
			Hell_drawRect(mouse_x + 8 , mouse_y - 40 , 8 * 12 , 8 * 7 , 0,0, 255,255,255,192);
			Hell_drawFont("X:" ~ std.string.toString(cursor_x) , mouse_x + 16 , mouse_y - 32);
			Hell_drawFont("Y:" ~ std.string.toString(cursor_y) , mouse_x + 16 , mouse_y - 24);
			
			if(map.inRange(cursor_x,cursor_y)){
				MapChip m = map.toMap(cursor_x,cursor_y);
				Hell_drawFont("G:" ~ std.string.toString(cast(int)m.grass) , mouse_x + 16 , mouse_y - 16);
				Hell_drawFont("GL:" ~ std.string.toString(cast(int)m.getGrassLevel()) , mouse_x + 16 , mouse_y - 8);
				Hell_drawFont("TYPE:" ~ MapChip.name[m.type] , mouse_x + 16 , mouse_y - 0);
			}
			
			// キャラクタ情報ウインドウ
			if(target && target.exist) target.drawStatus();
		}
		
		// 左上
		for(int t=0;t<Character.TYPE.MAX;t++){
			if(t == Character.TYPE.NONE) continue;
			
			Hell_drawFont(Character.type_name[t] ~ ":" ~ std.string.toString(charpool.count(cast(Character.TYPE)t)) , 8 , 8 * t);
		}
		
		menu.draw();
		chart_switch.draw();
		economy_switch.draw();
		speed_switch.draw();
		
		string buf;
		Hell_drawFont("TIME:" ~ std.string.toString(timer / 40) , getScreenWidth() - 80 , 32);
		
		if(chart_switch.getSelected() != "") chart.draw();
		
		Hell_drawFPS();
//		Hell_update();
	}
	
	// カーソルがマップを指しているか(メニュー等に指していないか
	bool onMouseMap(){
		if(menu.getMouseOver() == "" && economy_switch.getMouseOver() == ""
			&& chart_switch.getMouseOver() == "" && speed_switch.getMouseOver() == "") return true;
		
		return false;
	}
	
	// 画面サイズ取得
	int getScreenWidth(){return boot.g_width;}
	int getScreenHeight(){return boot.g_height;}
}


/********************************************************************************/
/*	チャート																	*/
/********************************************************************************/

class PlayChart{
	class Log{
		double[] param;
		
		this(int n){
			param = new double[n];
		}
		
		void set(int t,double p){
			param[t] = p;
		}
		
		int length(){return param.length;}
		double getMax(){
			double result = 0;
			foreach(p;param) if(p > result) result = p;
			return result;
		}
	}
	
	Log[] logs;
	GameMain gamemain;
	
	static const int LOG_MAX = 160;
	static const int LOG_VIEW_WIDTH = 4;
	
	this(GameMain gamemain){
		logs = new Log[ LOG_MAX ];
		foreach(inout l;logs) l = null;
		this.gamemain = gamemain;
	}
	
	// チャートを更新する
	void addChart(CharacterPool cp , Map map){
		for(int t=0;t<logs.length-1;t++){
			logs[t] = logs[t + 1];
		}
		
		Log newline = new Log(Character.TYPE.MAX + 1);
		for(int t=0;t<newline.length();t++){
			if(t == Character.TYPE.NONE) continue;
			
			if(t < Character.TYPE.MAX){
				newline.set(t , cp.count(cast(Character.TYPE)t));
			}else{
				newline.set(t , map.count(MapChip.TYPE.MOVIE));
			}
		}
		
		logs[length - 1] = newline;
	}
	
	// 作画
	void draw(){
		static const int r[] = [  0 ,   0 ,   0 ,   0 ,   0 , 255 , 128 ];
		static const int g[] = [  0 , 255 , 255 ,   0 ,   0 ,   0 , 128 ];
		static const int b[] = [  0 ,   0 , 255 ,   0 ,   0 ,   0 , 128 ];
		
		if(!logs[length - 1]) return;
		
		float scale = 2;
		while(gamemain.getScreenHeight() - 80 - logs[length - 1].getMax() * scale < 80){
			scale /= 2.0;
		}
		
		for(int t=0;t<logs.length - 1;t++){
			if(logs[t] && logs[t+1]){
				for(int e;e < logs[t].param.length ; e++){
					if(r[e] == 0 && g[e] == 0 && b[e] == 0) continue;
					
					Hell_drawLine(t * LOG_VIEW_WIDTH , gamemain.getScreenHeight() - 80 - logs[t].param[e] * scale
							, (t+1) * LOG_VIEW_WIDTH , gamemain.getScreenHeight() - 80 - logs[t+1].param[e] * scale
							, 2 , r[e] , g[e] , b[e]);
				}
			}
		}
	}
}
